﻿using System;
using System.Collections.Generic;
using PostSharp.Extensibility;
using System.Reflection;
using PostSharp.Sdk.CodeModel;
using PostSharp.Sdk.CodeWeaver;
using PostSharp.Sdk.Collections;
using PostSharp.Sdk.Extensibility;
using PostSharp.Sdk.Extensibility.Tasks;
using Young3.FMSearch.Core.Attributes;

namespace Young3.FMSearch.Core
{
    internal class FMPointerWeaveTask : Task, IAdviceProvider
    {
        protected override void Initialize()
        {
        }

        public void ProvideAdvices(Weaver codeWeaver)
        {
            // Gets the dictionary of custom attributes.
            AnnotationRepositoryTask annotationRepository =
                AnnotationRepositoryTask.GetTask(this.Project);

            // Requests an enumerator of all instances of our TraceAttribute.
            IEnumerator<IAnnotationInstance> customAttributeEnumerator =
                annotationRepository.GetAnnotationsOfType(typeof(FMPointerAttribute), false);

            // For each instance of our TraceAttribute.
            while (customAttributeEnumerator.MoveNext())
            {
                // Gets the method to which it applies.
                MethodDefDeclaration methodDef = customAttributeEnumerator.Current.TargetElement
                                                 as MethodDefDeclaration;

                if (methodDef != null)
                {
                    // Constructs a custom attribute instance.
                    FMPointerAttribute attribute =
                        (FMPointerAttribute)
                        CustomAttributeHelper.ConstructRuntimeObject(customAttributeEnumerator.Current.Value,
                                                                      typeof(FMPointerAttribute));

                    // Build an advice based on this custom attribute.
                    FMPointerWeaveAdvice advice = new FMPointerWeaveAdvice(this, attribute);

                    codeWeaver.AddMethodLevelAdvice(advice,
                                                     new Singleton<MethodDefDeclaration>(methodDef),
                                                     JoinPointKinds.BeforeMethodBody,
                                                     null);
                }
            }
        }
    }
}